package com.yesep.learn.netty.server.adapter;

import java.net.SocketAddress;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.yesep.learn.netty.protocol.session.SessionOnline;
import com.yesep.learn.netty.server.dispatcher.RequestDispatcher;

import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

/**
 * NettyServer通道适配器
 */
@Component
@Sharable
public class ServerChannelHandlerAdapter extends ChannelHandlerAdapter {
	private static final Logger log = LoggerFactory.getLogger(ServerChannelHandlerAdapter.class);
	@Resource
	private RequestDispatcher dispatcher;// 请求分排器

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		Channel channel = ctx.channel();
		SocketAddress remoteAddr = channel.remoteAddress();
		log.error("站点通讯异常离线   ID={} remoteAddress={}", channel.id(), remoteAddr);
		log.error(cause.getMessage(), cause);
		ctx.close();
	}

	/**
	 * 服务器接收到消息时进行进行的处理
	 *
	 * @param ctx
	 *            channelHandlerContext
	 * @param msg
	 *            msg
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) {
		if (null == msg || "".equals(msg) || !(msg instanceof String)) {
			Channel channel = ctx.channel();
			String remoteAddr = channel.remoteAddress().toString();
			log.error("错误报文   ID={} remoteAddress={}  message={}", channel.id(), remoteAddr, msg);
			SessionOnline.errorCount(remoteAddr);//累加错误次数
			if (SessionOnline.danger(remoteAddr)) {//判断是否异常连接
				ctx.close();
			}
			return;
		}
		SessionOnline.online(ctx);//更新在线状态
		this.dispatcher.dispatcher(ctx, (String) msg);// 报文处理
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		super.channelReadComplete(ctx);
		ctx.flush();
	}

	/**
	 * 触发器
	 *
	 * @param ctx
	 *            channelHandlerContext
	 * @param evt
	 * @throws Exception
	 *             exception
	 */
	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		Channel channel = ctx.channel();
		String remoteAddr = channel.remoteAddress().toString();
		if (evt instanceof IdleStateEvent) {//心跳包超时
			if (((IdleStateEvent) evt).state() == IdleState.READER_IDLE) {
				log.info("站点心跳包超时  ID={} remoteAddress={}", channel.id(), remoteAddr);
				ctx.close();
			}
		} else {
			super.userEventTriggered(ctx, evt);
		}
	}

	@Override
	public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
		super.channelRegistered(ctx);
		Channel channel = ctx.channel();
		SocketAddress remoteAddr = channel.remoteAddress();
		log.info("新建连接   ID={} remoteAddress={}", channel.id(), remoteAddr);
		//由于些时没有报文内容，不能判断是否正常连接，此时不能添加在线站点
	}

	//注销连接，只要程序中有执行到ctx.close()最后都会调用此方法
	@Override
	public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
		super.channelUnregistered(ctx);
		Channel channel = ctx.channel();
		SocketAddress remoteAddr = channel.remoteAddress();
		log.info("站点离线   ID={} remoteAddress={}", channel.id(), remoteAddr);
		SessionOnline.offline(remoteAddr.toString());
	}
}
